/*
Copyright 2024 New Vector Ltd.
Copyright 2017 Vector Creations Ltd
Copyright 2016 OpenMarket Ltd

SPDX-License-Identifier: AGPL-3.0-only
Please see LICENSE in the repository root for full details.
 */

#import "StartChatViewController.h"

#import "GeneratedInterface-Swift.h"
#import "MXSession+Riot.h"

@interface StartChatViewController () <UITableViewDataSource, UISearchBarDelegate, ContactsTableViewControllerDelegate, InviteFriendsHeaderViewDelegate>
{
    // The contact used to describe the current user.
    MXKContact *userContact;
    
    // Section indexes
    NSInteger participantsSection;
    
    // The current list of participants.
    NSMutableArray<MXKContact*> *participants;
    
    // Navigation bar items
    UIBarButtonItem *cancelBarButtonItem;
    UIBarButtonItem *createBarButtonItem;
    
    // SearchBar text
    NSString *currentSearch;
    
    // HTTP Request
    MXHTTPOperation *roomCreationRequest;
    
    // This dictionary tells for each display name whether it appears several times in participants list
    NSMutableDictionary <NSString*, NSNumber*> *isMultiUseNameByDisplayName;
}

@property (weak, nonatomic) IBOutlet UIView *searchBarHeader;
@property (weak, nonatomic) IBOutlet UISearchBar *searchBarView;
@property (weak, nonatomic) IBOutlet UIView *searchBarHeaderBorder;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *searchBarHeaderHeightConstraint;

@property (nonatomic, strong) InviteFriendsPresenter *inviteFriendsPresenter;
@property (nonatomic, weak) InviteFriendsHeaderView *inviteFriendsHeaderView;

@property (nonatomic, weak) UIView *onlyOneEmailInvitationView;

@end

@implementation StartChatViewController

#pragma mark - Class methods

+ (UINib *)nib
{
    return [UINib nibWithNibName:NSStringFromClass([StartChatViewController class])
                          bundle:[NSBundle bundleForClass:[StartChatViewController class]]];
}

+ (instancetype)startChatViewController
{
    return [[[self class] alloc] initWithNibName:NSStringFromClass([StartChatViewController class])
                                          bundle:[NSBundle bundleForClass:[StartChatViewController class]]];
}

#pragma mark -

- (void)finalizeInit
{
    [super finalizeInit];
    
    _isAddParticipantSearchBarEditing = NO;
    
    // Prepare room participants
    participants = [NSMutableArray array];
    
    // Assign itself as delegate
    self.contactsTableViewControllerDelegate = self;
    
    self.screenTracker = [[AnalyticsScreenTracker alloc] initWithScreen:AnalyticsScreenStartChat];
}

- (void)viewDidLoad
{
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.

    self.navigationItem.title = [VectorL10n roomCreationTitle];
    
    // Add each matrix session by default.
    NSArray *sessions = [AppDelegate theDelegate].mxSessions;
    for (MXSession *mxSession in sessions)
    {
        [self addMatrixSession:mxSession];
    }

    // Prepare its data source
    ContactsDataSource *dataSource = [[ContactsDataSource alloc] initWithMatrixSession:self.mainSession]; // TO TEST
    dataSource.areSectionsShrinkable = YES;
    dataSource.displaySearchInputInContactsList = YES;
    dataSource.forceMatrixIdInDisplayName = YES;
    // Add a plus icon to the contact cell when a search session is in progress,
    // in order to make it more understandable for the end user.
    dataSource.contactCellAccessoryImage = [AssetImages.plusIcon.image vc_tintedImageUsingColor:ThemeService.shared.theme.textPrimaryColor];

    [self displayList:dataSource];

    cancelBarButtonItem = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(onButtonPressed:)];
    self.navigationItem.leftBarButtonItem = cancelBarButtonItem;
    
    createBarButtonItem = [[UIBarButtonItem alloc] initWithTitle:[VectorL10n start] style:UIBarButtonItemStylePlain target:self action:@selector(onButtonPressed:)];
    self.navigationItem.rightBarButtonItem = createBarButtonItem;
    
    _searchBarView.placeholder = [VectorL10n roomCreationInviteAnotherUser];
    _searchBarView.returnKeyType = UIReturnKeyDone;
    _searchBarView.autocapitalizationType = UITextAutocapitalizationTypeNone;    
    [self refreshSearchBarItemsColor:_searchBarView];
    
    [self.contactsTableView registerClass:ContactTableViewCell.class forCellReuseIdentifier:@"ParticipantTableViewCellId"];
    
    // Redirect table data source
    self.contactsTableView.dataSource = self;
    
    [self setupInviteFriendsHeaderView];
}

- (void)setupInviteFriendsHeaderView
{
    if (self.inviteFriendsHeaderView)
    {
        return;
    }
    
    if (!RiotSettings.shared.allowInviteExernalUsers)
    {
        self.contactsTableView.tableHeaderView = nil;
        return;
    }
    
    InviteFriendsHeaderView *inviteFriendsHeaderView = [InviteFriendsHeaderView instantiate];
    inviteFriendsHeaderView.delegate = self;
    self.contactsTableView.tableHeaderView = inviteFriendsHeaderView;
    
    self.inviteFriendsHeaderView = inviteFriendsHeaderView;
}

- (void)showInviteFriendsHeaderView:(BOOL)show
{
    if (show)
    {
        if (!self.inviteFriendsHeaderView)
        {
            [self setupInviteFriendsHeaderView];
        }
    }
    else if (self.inviteFriendsHeaderView != nil)
    {
        self.contactsTableView.tableHeaderView = nil;
    }
}

- (void)userInterfaceThemeDidChange
{
    [super userInterfaceThemeDidChange];
    
    [self refreshSearchBarItemsColor:_searchBarView];
    
    // Check the table view style to select its bg color.
    self.contactsTableView.backgroundColor = ((self.contactsTableView.style == UITableViewStylePlain) ? ThemeService.shared.theme.baseColor : ThemeService.shared.theme.headerBackgroundColor);
    self.view.backgroundColor = self.contactsTableView.backgroundColor;
    self.contactsTableView.separatorColor = ThemeService.shared.theme.lineBreakColor;
    
    _searchBarHeaderBorder.backgroundColor = self.contactsTableView.backgroundColor;
    
    if (self.contactsTableView.dataSource)
    {
        [self.contactsTableView reloadData];
    }
    
    [self.inviteFriendsHeaderView updateWithTheme:ThemeService.shared.theme];
}

- (UIStatusBarStyle)preferredStatusBarStyle
{
    return ThemeService.shared.theme.statusBarStyle;
}

- (void)destroy
{
    if (roomCreationRequest)
    {
        [roomCreationRequest cancel];
        roomCreationRequest = nil;
    }
    
    cancelBarButtonItem = nil;
    createBarButtonItem = nil;
    
    isMultiUseNameByDisplayName = nil;
    
    participants = nil;
    
    [super destroy];
}

- (void)addMatrixSession:(MXSession *)mxSession
{
    [super addMatrixSession:mxSession];
    
    // FIXME: Handle multi accounts
    NSString *displayName = [VectorL10n you];
    userContact = [[MXKContact alloc] initMatrixContactWithDisplayName:displayName andMatrixID:self.mainSession.myUser.userId];
    
    [self refreshParticipants];
}

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    
    // Active the search session if the current participant list is empty
    if (!participants.count)
    {
        self.isAddParticipantSearchBarEditing = YES;
    }
    else
    {
        // Refresh display
        [self refreshContactsTable];
    }
}

- (void)viewDidDisappear:(BOOL)animated
{
    [super viewDidDisappear:animated];

    // cancel any pending search
    [self searchBarCancelButtonClicked:_searchBarView];
}

- (void)viewDidLayoutSubviews
{
    [super viewDidLayoutSubviews];
    [self.contactsTableView vc_relayoutHeaderView];
}

#pragma mark -

- (void)setIsAddParticipantSearchBarEditing:(BOOL)isAddParticipantSearchBarEditing
{
    if (_isAddParticipantSearchBarEditing != isAddParticipantSearchBarEditing)
    {
        if (isAddParticipantSearchBarEditing)
        {
            self.navigationItem.rightBarButtonItem = nil;
        }
        else
        {
            self.navigationItem.rightBarButtonItem = createBarButtonItem;
            
            [self refreshParticipants];
        }
        
        _isAddParticipantSearchBarEditing = isAddParticipantSearchBarEditing;
        
        // Switch the display between search result and participants list
        [self refreshContactsTable];
    }
}

#pragma mark - Internals

- (void)refreshParticipants
{
    // Refer all participants in ignored contacts dictionary.
    isMultiUseNameByDisplayName = [NSMutableDictionary dictionary];
    [contactsDataSource.ignoredContactsByMatrixId removeAllObjects];
    [contactsDataSource.ignoredContactsByEmail removeAllObjects];
    
    for (MXKContact* contact in participants)
    {
        NSArray *identifiers = contact.matrixIdentifiers;
        if (identifiers.count)
        {
            // Here the contact can only have one identifier
            contactsDataSource.ignoredContactsByMatrixId[identifiers.firstObject] = contact;
        }
        else
        {
            NSArray *emails = contact.emailAddresses;
            if (emails.count)
            {
                // Here the contact can only have one email
                MXKEmail *email = emails.firstObject;
                contactsDataSource.ignoredContactsByEmail[email.emailAddress] = contact;
            }
        }
        isMultiUseNameByDisplayName[contact.displayName] = (isMultiUseNameByDisplayName[contact.displayName] ? @(YES) : @(NO));
    }
    
    if (userContact)
    {
        if (self.mainSession.myUser.userId)
        {
            contactsDataSource.ignoredContactsByMatrixId[self.mainSession.myUser.userId] = userContact;
        }
    }
    
    // hide the search bar if a participant is already invited by email
    BOOL hideSearchBar = [self participantsAlreadyContainAnEmail];
    self.searchBarHeader.alpha = hideSearchBar ? 0.0f : 1.0f;
    self.searchBarHeaderHeightConstraint.constant = hideSearchBar ? 0.0f : 50.0f;
    [UIView animateWithDuration:0.2f animations:^{
        [self.view layoutIfNeeded];
    }];
}

- (BOOL)participantsAlreadyContainAnEmail
{
    for (MXKContact* participant in participants)
    {
        // if it is not a matrix contact or a local contact with a MatrixID
        if (participant.matrixIdentifiers.count == 0 && ![MXTools isMatrixUserIdentifier:participant.displayName])
        {
            return YES;
        }
    }
    return NO;
}

- (BOOL)canAddParticipant: (MXKContact*) contact
{
    if (!contact)
    {
        return YES;
    }

    // The following rules will be applied only if the resulting room is going to be encrypted
    if (![self.mainSession vc_homeserverConfiguration].encryption.isE2EEByDefaultEnabled)
    {
        return YES;
    }

    // If we have already invited an email, we cannot add another participant
    if ([self participantsAlreadyContainAnEmail])
    {
        return NO;
    }
        
    // if it is not a matrix contact, nor a local contact with a MatrixID, and if there is already at least one participant, another participant cannot be added.
    if ((contact.matrixIdentifiers.count == 0 && ![MXTools isMatrixUserIdentifier:contact.displayName]) && participants.count > 0)
    {
        return NO;
    }
        
    // Otherwise, we should be able to add this participant
    return YES;
}

- (void)showAllowOnlyOneInvitByEmailAllowedHeaderView:(BOOL)visible
{
    if (visible)
    {
        if (!self.onlyOneEmailInvitationView)
        {
            UIView *headerView = [[UIView alloc] initWithFrame: CGRectZero];
            headerView.translatesAutoresizingMaskIntoConstraints = NO;
            
            UILabel *label = [[UILabel alloc] initWithFrame: CGRectZero];
            label.numberOfLines = 0;
            label.textColor = ThemeService.shared.theme.textSecondaryColor;
            label.font = [UIFont systemFontOfSize:14 weight:UIFontWeightLight];
            label.adjustsFontSizeToFitWidth = YES;

            label.text = VectorL10n.roomCreationOnlyOneEmailInvite;
            label.translatesAutoresizingMaskIntoConstraints = NO;
            [headerView addSubview:label];
            
            [NSLayoutConstraint activateConstraints:@[
                [label.leadingAnchor constraintEqualToAnchor:headerView.leadingAnchor constant:16],
                [label.trailingAnchor constraintEqualToAnchor:headerView.trailingAnchor constant:-16],
                [label.topAnchor constraintEqualToAnchor:headerView.topAnchor constant:8],
                [label.bottomAnchor constraintEqualToAnchor:headerView.bottomAnchor constant:-8],
            ]];
            [label setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
            [headerView setContentCompressionResistancePriority:UILayoutPriorityRequired forAxis:UILayoutConstraintAxisVertical];
                                    
            self.onlyOneEmailInvitationView = headerView;
            self.contactsTableView.tableHeaderView = self.onlyOneEmailInvitationView;
            
            [NSLayoutConstraint activateConstraints:@[
                [headerView.leadingAnchor constraintEqualToAnchor:self.contactsTableView.safeAreaLayoutGuide.leadingAnchor],
                [headerView.trailingAnchor constraintEqualToAnchor:self.contactsTableView.safeAreaLayoutGuide.trailingAnchor]
            ]];
            [self.contactsTableView.tableHeaderView layoutIfNeeded];
        }
    }
    else if (self.onlyOneEmailInvitationView != nil)
    {
        if (self.contactsTableView.tableHeaderView == self.onlyOneEmailInvitationView)
        {
            self.contactsTableView.tableHeaderView = nil;
        }
        self.onlyOneEmailInvitationView = nil;
    }
}

- (void)showInviteFriendsFromSourceView:(UIView*)sourceView
{
    if (!self.inviteFriendsPresenter)
    {
        self.inviteFriendsPresenter = [InviteFriendsPresenter new];
    }
    
    NSString *userId = self.mainSession.myUser.userId;
    
    [self.inviteFriendsPresenter presentFor:userId
                                       from:self
                                 sourceView:sourceView
                                   animated:YES];
}


#pragma mark - UITableView data source

- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
    NSInteger count = 0;
    
    // Do not show invite friends action when a participant is selected
    [self showInviteFriendsHeaderView:!participants.count];
    
    if (_isAddParticipantSearchBarEditing)
    {
        participantsSection = -1;
        count = [contactsDataSource numberOfSectionsInTableView:tableView];
    }
    else
    {
        participantsSection = count++;
    }
    
    return count;
}

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    NSInteger count = 0;
    
    if (_isAddParticipantSearchBarEditing)
    {
        count = [contactsDataSource tableView:tableView numberOfRowsInSection:section];
    }
    else if (section == participantsSection)
    {
        count = participants.count + 1;
    }
    
    return count;
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
    UITableViewCell *cell;
    
    if (_isAddParticipantSearchBarEditing)
    {
        cell = [contactsDataSource tableView:tableView cellForRowAtIndexPath:indexPath];
        MXKContact* contact = [contactsDataSource contactAtIndexPath:indexPath];
        if (![self canAddParticipant:contact])
        {
            // Prevent to add it
            cell.contentView.alpha = 0.5;
            cell.userInteractionEnabled = NO;
            cell.accessoryView = nil;
        }
    }
    else if (indexPath.section == participantsSection)
    {
        ContactTableViewCell* participantCell = [tableView dequeueReusableCellWithIdentifier:@"ParticipantTableViewCellId" forIndexPath:indexPath];
        
        MXKContact *contact;
        
        if (indexPath.row == 0)
        {
            // oneself dedicated cell
            contact = userContact;
        }
        else
        {
            NSInteger index = indexPath.row - 1;
            
            if (index < participants.count)
            {
                contact = participants[index];
                
                // Disambiguate the display name when it appears several times.
                if (contact.displayName)
                {
                    participantCell.showMatrixIdInDisplayName = [isMultiUseNameByDisplayName[contact.displayName] isEqualToNumber:@(YES)];
                }
            }
        }
        
        participantCell.selectionStyle = UITableViewCellSelectionStyleNone;
        [participantCell render:contact];
        
        cell = participantCell;
    }
    else
    {
        // Return a fake cell to prevent app from crashing.
        cell = [[UITableViewCell alloc] init];
    }
    
    return cell;
}

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (indexPath.section == participantsSection && indexPath.row != 0)
    {
        return YES;
    }
    return NO;
}

- (void)tableView:(UITableView*)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath
{
    // iOS8 requires this method to enable editing (see editActionsForRowAtIndexPath).
}

#pragma mark - UITableView delegate

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath;
{
    cell.backgroundColor = ThemeService.shared.theme.backgroundColor;
    
    // Update the selected background view
    if (ThemeService.shared.theme.selectedBackgroundColor)
    {
        cell.selectedBackgroundView = [[UIView alloc] init];
        cell.selectedBackgroundView.backgroundColor = ThemeService.shared.theme.selectedBackgroundColor;
    }
    else
    {
        if (tableView.style == UITableViewStylePlain)
        {
            cell.selectedBackgroundView = nil;
        }
        else
        {
            cell.selectedBackgroundView.backgroundColor = nil;
        }
    }
}

- (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section
{
    CGFloat height = 0.0;
    
    if (_isAddParticipantSearchBarEditing)
    {
        height = [contactsDataSource heightForHeaderInSection:section];
    }
    
    return height;
}

- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (_isAddParticipantSearchBarEditing)
    {
        return [super tableView:tableView heightForRowAtIndexPath:indexPath];
    }
    
    return 74;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    if (_isAddParticipantSearchBarEditing)
    {
        [super tableView:tableView didSelectRowAtIndexPath:indexPath];
    }
    else
    {
        // Do nothing
        [tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
}

- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSMutableArray* actions;
    
    // add the swipe to delete only on participants sections
    if (indexPath.section == participantsSection && indexPath.row != 0)
    {
        actions = [[NSMutableArray alloc] init];
        
        // Patch: Force the width of the button by adding whitespace characters into the title string.
        UITableViewRowAction *leaveAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"        "  handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
            
            [self onDeleteAt:indexPath];
        
        }];
        
        leaveAction.backgroundColor = [MXKTools convertImageToPatternColor:@"remove_icon" backgroundColor:ThemeService.shared.theme.headerBackgroundColor patternSize:CGSizeMake(74, 74) resourceSize:CGSizeMake(24, 24)];
        [actions insertObject:leaveAction atIndex:0];
    }
    
    return actions;
}

#pragma mark - Actions

- (void)onDeleteAt:(NSIndexPath*)path
{
    NSInteger row = path.row;
    row --;
    
    if (row < participants.count)
    {
        [participants removeObjectAtIndex:row];
        
        [self refreshParticipants];
        
        [self refreshContactsTable];
    }
}

- (IBAction)onButtonPressed:(id)sender
{
    if (sender == createBarButtonItem)
    {
        // Disable button to prevent multiple request
        createBarButtonItem.enabled = NO;
        [self startActivityIndicator];
        
        // Prepare the invited participant data
        NSMutableArray *inviteArray = [NSMutableArray array];
        NSMutableArray<MXInvite3PID *> *invite3PIDArray = [NSMutableArray array];
        
        // Check whether some users must be invited
        for (MXKContact *contact in participants)
        {
            NSArray *identifiers = contact.matrixIdentifiers;
            if (identifiers.count)
            {
                [inviteArray addObject:identifiers.firstObject];
            }
            else
            {
                // This is a text entered by the user, or a local contact
                NSString *participantId;
                
                if (contact.emailAddresses.count)
                {
                    // This is a local contact, consider the first email by default.
                    // TODO: Prompt the user to select the right email.
                    MXKEmail *email = contact.emailAddresses.firstObject;
                    participantId = email.emailAddress;
                }
                else
                {
                    // This is the text filled by the user.
                    participantId = contact.displayName;
                }
                
                // Is it an email or a Matrix user ID?
                if ([MXTools isEmailAddress:participantId])
                {
                    // The identity server must be defined
                    if (!self.mainSession.matrixRestClient.identityServer)
                    {
                        MXLogDebug(@"[StartChatViewController] Invite %@ failed", participantId);
                        continue;
                    }
                    
                    // The hostname of the identity server must not have the protocol part
                    NSString *identityServer = self.mainSession.matrixRestClient.identityServer;
                    if ([identityServer hasPrefix:@"http://"] || [identityServer hasPrefix:@"https://"])
                    {
                        identityServer = [identityServer substringFromIndex:[identityServer rangeOfString:@"://"].location + 3];
                    }
                    
                    MXInvite3PID *invite3PID = [[MXInvite3PID alloc] init];
                    invite3PID.identityServer = identityServer;
                    invite3PID.medium = kMX3PIDMediumEmail;
                    invite3PID.address = participantId;
                    
                    [invite3PIDArray addObject:invite3PID];
                }
                else
                {
                    [inviteArray addObject:participantId];
                }
            }
        }
        
        // Is it a direct chat?
        BOOL isDirect = ((inviteArray.count + invite3PIDArray.count == 1) ? YES : NO);
       
        // In case of a direct chat with only one user id, we open the first available direct chat
        // or creates a new one (if it doesn't exist).
        if (isDirect && inviteArray.count)
        {
            [[AppDelegate theDelegate] startDirectChatWithUserId:inviteArray.firstObject completion:^{
                self->createBarButtonItem.enabled = YES;
                [self stopActivityIndicator];
            }];
        }
        else
        {
            // We don't want to create a new direct room for a 3rd party invite if we already have one
            NSString *first3rdPartyInvitee = invite3PIDArray.firstObject.address;
            if (isDirect && first3rdPartyInvitee)
            {
                MXRoom *existingRoom = [self.mainSession directJoinedRoomWithUserId:first3rdPartyInvitee];
                if (existingRoom)
                {
                    [self stopActivityIndicator];
                    [[AppDelegate theDelegate] showRoom:existingRoom.roomId andEventId:nil withMatrixSession:self.mainSession];
                    return;
                }
            }
            
            // Ensure direct chat are created with equal ops on both sides (the trusted_private_chat preset)
            MXRoomPreset preset = (isDirect ? kMXRoomPresetTrustedPrivateChat : nil);

            MXWeakify(self);
            void (^onFailure)(NSError *) = ^(NSError *error){
                MXStrongifyAndReturnIfNil(self);

                self->createBarButtonItem.enabled = YES;

                self->roomCreationRequest = nil;
                [self stopActivityIndicator];

                MXLogDebug(@"[StartChatViewController] Create room failed");

                // Alert user
                [[AppDelegate theDelegate] showAlertWithTitle:nil message:[VectorL10n roomCreationDmError]];
            };

            [self.mainSession vc_canEnableE2EByDefaultInNewRoomWithUsers:inviteArray success:^(BOOL canEnableE2E) {
                MXStrongifyAndReturnIfNil(self);

                // Create new room
                MXRoomCreationParameters *roomCreationParameters = [MXRoomCreationParameters new];
                roomCreationParameters.visibility = kMXRoomDirectoryVisibilityPrivate;
                roomCreationParameters.inviteArray = inviteArray.count ? inviteArray : nil;
                roomCreationParameters.invite3PIDArray = invite3PIDArray.count ? invite3PIDArray : nil;
                roomCreationParameters.isDirect = isDirect;
                roomCreationParameters.preset = preset;

                if (canEnableE2E)
                {
                    roomCreationParameters.initialStateEvents = @[
                                                                  [MXRoomCreationParameters initialStateEventForEncryptionWithAlgorithm:kMXCryptoMegolmAlgorithm
                                                                   ]];
                }

                self->roomCreationRequest = [self.mainSession createRoomWithParameters:roomCreationParameters success:^(MXRoom *room) {

                    // Update the room summary
                    [room.summary resetRoomStateData];
                    
                    self->roomCreationRequest = nil;

                    [self stopActivityIndicator];

                    Analytics.shared.viewRoomTrigger = AnalyticsViewRoomTriggerCreated;
                    [[AppDelegate theDelegate] showRoom:room.roomId andEventId:nil withMatrixSession:self.mainSession];

                } failure:onFailure];

            } failure:onFailure];
        }
    }
    else if (sender == self.navigationItem.leftBarButtonItem)
    {
        // Cancel has been pressed
        if (_isAddParticipantSearchBarEditing && participants.count)
        {
            // Cancel the search process
            [self searchBarCancelButtonClicked:_searchBarView];
        }
        else
        {
            // Cancel the new chat creation
            [self.navigationController dismissViewControllerAnimated:YES completion:nil];
        }
    }
}

#pragma mark - UISearchBar delegate

- (void)refreshSearchBarItemsColor:(UISearchBar *)searchBar
{
    // bar tint color
    searchBar.barTintColor = searchBar.tintColor = ThemeService.shared.theme.tintColor;
    
    // FIXME: this all seems incredibly fragile and tied to gutwrenching the current UISearchBar internals.

    // text color
    UITextField *searchBarTextField = searchBar.vc_searchTextField;
    searchBarTextField.textColor = ThemeService.shared.theme.textSecondaryColor;
    
    // Magnifying glass icon.
    UIImageView *leftImageView = (UIImageView *)searchBarTextField.leftView;
    leftImageView.image = [leftImageView.image imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
    leftImageView.tintColor = ThemeService.shared.theme.textSecondaryColor;
    
    // Use the theme's grey color.
    // The effect views are needed due to minimal style.
    // With default style there is a border above the search bar.
    searchBarTextField.backgroundColor = ThemeService.shared.theme.textQuinaryColor;
    UIView *effectBackgroundTop = [searchBarTextField valueForKey:@"_effectBackgroundTop"];
    UIView *effectBackgroundBottom = [searchBarTextField valueForKey:@"_effectBackgroundBottom"];
    effectBackgroundTop.hidden = YES;
    effectBackgroundBottom.hidden = YES;
}

- (void)searchBar:(UISearchBar *)searchBar textDidChange:(NSString *)searchText
{
    self->currentSearch = searchText;
    if (searchText != nil && searchText.length > 0)
    {
        MXKContact *contact = nil;
        if ([MXTools isMatrixUserIdentifier:searchText])
        {
            contact = [[MXKContact alloc] initMatrixContactWithDisplayName:searchText andMatrixID:searchText];

        }
        else if ([MXTools isEmailAddress:searchText])
        {
            contact = [[MXKContact alloc] initContactWithDisplayName:searchText emails:nil phoneNumbers:nil andThumbnail:nil];
        }
        
        [self showAllowOnlyOneInvitByEmailAllowedHeaderView: ![self canAddParticipant:contact]];
    }
    else
    {
        [self showAllowOnlyOneInvitByEmailAllowedHeaderView:NO];
    }
    
    [contactsDataSource searchWithPattern:searchText forceReset:NO];
    self.contactsAreFilteredWithSearch = searchText.length ? YES : NO;
}

- (BOOL)searchBarShouldBeginEditing:(UISearchBar *)searchBar
{
    self.isAddParticipantSearchBarEditing = YES;
    searchBar.showsCancelButton = NO;
    
    return YES;
}

- (void)searchBarCancelButtonClicked:(UISearchBar *)searchBar
{
    searchBar.text = nil;
    self->currentSearch = nil;
    self.isAddParticipantSearchBarEditing = NO;
    
    // Reset filtering
    [contactsDataSource searchWithPattern:nil forceReset:NO];
    
    // Leave search
    [searchBar resignFirstResponder];
    
    [self showAllowOnlyOneInvitByEmailAllowedHeaderView:NO];
}

#pragma mark - ContactsTableViewControllerDelegate

- (void)contactsTableViewController:(ContactsTableViewController *)contactsTableViewController didSelectContact:(MXKContact*)contact
{
    // If contact has only an email the identity server must be defined
    if (!self.mainSession.matrixRestClient.identityServer && contact.matrixIdentifiers.count == 0)
    {
        NSString *participantId;
        
        if (contact.emailAddresses.count)
        {
            MXKEmail *email = contact.emailAddresses.firstObject;
            participantId = email.emailAddress;
        }
        else
        {
            // This is the text filled by the user.
            participantId = contact.displayName;
        }
        
        if ([MXTools isEmailAddress:participantId])
        {
            MXLogDebug(@"[StartChatViewController] No identity server is configured, do not add participant with email");
            
            [contactsTableViewController refreshCurrentSelectedCell:YES];
            
            UIAlertController *alert = [UIAlertController alertControllerWithTitle:[VectorL10n error]
                                                                           message:[VectorL10n roomCreationErrorInviteUserByEmailWithoutIdentityServer]
                                                                    preferredStyle:UIAlertControllerStyleAlert];
            [alert addAction:[UIAlertAction actionWithTitle:[VectorL10n ok] style:UIAlertActionStyleDefault handler:nil]];
            [self presentViewController:alert animated:YES completion:nil];
            
            return;
        }
    }
    
    if ([self canAddParticipant:contact])
    {
        // Update here the mutable list of participants
        [participants addObject:contact];
        
        // Refresh display by leaving search session
        [self searchBarCancelButtonClicked:_searchBarView];
    }
}

#pragma mark - InviteFriendsHeaderViewDelegate

- (void)inviteFriendsHeaderView:(InviteFriendsHeaderView *)headerView didTapButton:(UIButton *)button

{
    [self showInviteFriendsFromSourceView:button];
}

@end
